home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_097 / splines / popmenu.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  9KB  |  259 lines

  1. /* The routines in this file are copyright (c) 1987 by Helene (Lee) Taran.
  2.  * Permission is granted for use and free distribution as long as the
  3.  * original author's name is included with the code.
  4.  */
  5.  
  6. #include "popmenu.h"
  7.  
  8. struct Layer_Info *PopUp_LayerInfo;
  9. struct TextFont *menufont;
  10.  
  11. /* User should call Init_MenuPackage() before trying to pop up any
  12.  * menus. Will return TRUE if the package has been initialized correctly.
  13.  * Do not attempt to use this package if this initialization routine 
  14.  * returns FALSE.
  15.  */
  16. Init_MenuPackage()
  17.   void *NewLayerInfo(), *OpenFont();
  18.   static struct TextAttr MenuFont = {(UBYTE *)"topaz.font",8,0,0};
  19.  
  20.   if (!(menufont = OpenFont(&MenuFont))) {
  21.      fprintf(stderr,"sorry couldn't find topaz eight for menu font]\n");
  22.      return(FALSE);
  23.   }
  24.   if (!(PopUp_LayerInfo = (struct Layer_Info *)NewLayerInfo()))  {
  25.      fprintf(stderr,"sorry, couldn't allocate a layer info structure\n");
  26.      return(FALSE);
  27.   }
  28.   return(TRUE);
  29. }
  30.  
  31. /* The user should call Close_MenuPackage before exiting their program
  32.  * to ensure that the menu package releases any memory that it
  33.  * has allocated for its own use. 
  34.  */
  35. Close_MenuPackage()
  36. {
  37.   CloseFont(menufont);
  38.   if (PopUp_LayerInfo != NULL)
  39.      DisposeLayerInfo(PopUp_LayerInfo);
  40.   
  41. }
  42.  
  43. Init_PopUp_Menu (menu)
  44. struct PopUp_Menu *menu;
  45. {
  46.   void *AllocRaster();
  47.  
  48.   struct PopUp_Item *item;
  49.   int longest = 0;
  50.   int total_height = 0;
  51.   int i;
  52.  
  53.   if (menu == NULL) return(FALSE);
  54.   item = menu->first_item;
  55.   while (item != NULL) {
  56.     /* note: bad things may happen if you allocate an empty string for
  57.      * your item text.
  58.      */
  59.      item->width = MAX(item->width, FONT_WIDTH * strlen(item->text));
  60.      item->left  = MAX(0,item->left);
  61.      longest = MAX(longest, (item->width + item->left));
  62.      item->height = MAX(item->height, FONT_HEIGHT);
  63.      item->top = MAX(0,item->top);
  64.      total_height += (item->height + item->top);
  65.     /* re-initialize item-top to be the top relative to the menu top */
  66.      item->top = (total_height  - item->height); 
  67.      item = item->next;
  68.   }
  69.   menu->height = total_height+1;
  70.   menu->width  = MAX(menu->width, longest);
  71.   
  72.   /* initialize a bitmap the same size as the required menu image  */
  73.   /* initialize a raster port to facillitate drawing into the bitmap */
  74.   InitBitMap(&(menu->bitmap),menu->depth,menu->width,menu->height);
  75.   InitRastPort(&(menu->rp));  
  76.   SetFont(menu->rp,menufont);
  77.   for (i = 0; i < menu->depth; i++) 
  78.     if (!(menu->bitmap.Planes[i] = (PLANEPTR)
  79.          AllocRaster(menu->width, menu->height))) {
  80.          Dispose_PopUp(menu);
  81.          return(FALSE);
  82.     }
  83.   menu->rp.BitMap = &(menu->bitmap); 
  84.   menu->cr.BitMap = &(menu->bitmap);
  85.  
  86.   /* draw the menu outline and background color into its own bitmap */
  87.   SetDrMd(&(menu->rp),JAM1);
  88.   SetAPen(&(menu->rp),menu->area_color);
  89.   SetOPen(&(menu->rp),menu->outline_color);
  90.  
  91.   RectFill(&(menu->rp),0,0,menu->width -1,menu->height -1);  
  92.   BNDRYOFF(&(menu->rp));  /* turn off the raster port outlining */
  93.  
  94.   item = menu->first_item;  
  95.    
  96.   /* Now, draw each menu item */
  97.   while (item != NULL) {
  98.      SetAPen(&(menu->rp),item->color);
  99.      Move(&(menu->rp),item->left, item->top + FONT_BASELINE);
  100.      Text(&(menu->rp),item->text, strlen(item->text));
  101.      item = item->next;
  102.   }
  103.   return(TRUE);
  104. }
  105.  
  106. /* SelectItem : activates the item located at <x,y>. Assumes the <menu>
  107.  * is currently active and thus, menu->left and menu->top should represent
  108.  * the menu's current top,left corner.  If there is an item located
  109.  * at <x,y> within the menu, then it is made 'active' ...this means
  110.  * that the item becomes menu->active_item and is highlighted. The
  111.  * old menu->active_item, if any, is deselected. Note: if you're using
  112.  * a GIMMEZEROZERO window you'll have to fiddle with the x,y coordinates.
  113.  */
  114. SelectItem(menu,Window)
  115. struct PopUp_Menu *menu;
  116. struct Window *Window;
  117. {  struct PopUp_Item *item;
  118.  
  119.    SHORT x = Window->MouseX + Window->LeftEdge;
  120.    SHORT y = Window->MouseY + Window->TopEdge;
  121.   
  122.    item = menu->first_item;
  123.    x -= menu->left;  y -= menu->top;
  124.    if ((x >= 0) && (x < menu->width) && (y >= 0) && (y < menu->height))
  125.       while (item != NULL) { 
  126.          if ((y >= item->top -1) && (y < item->top -1 + item->height))
  127.              break; /* we found an active item {yeah yeah...bad style, i know...} */
  128.           else item = item->next;
  129.          }
  130.    else item = NULL;    /* mouse isn't on menu */
  131.  
  132.    if (menu->active_item != item) {     /* deselect previously active item */
  133.       ComplementItem(menu,menu->active_item,Window);
  134.       ComplementItem(menu,item,Window);
  135.    }
  136.    menu->active_item = item;
  137. }
  138.        
  139.         
  140.    
  141.          
  142. /* ComplementItem : complements the given menu item area.  Assumes that
  143.  * the <menu> is currently being displayed and thus,the current menu->left
  144.  * and menu->top represent the current coordinates of the menu's top,left
  145.  * corner.  Assumes the <item> is  an popup_item that belongs to <menu>
  146.  * and that its left/top offsets have been initialized.
  147.  */
  148. ComplementItem(menu,item,Window)
  149. struct PopUp_Menu *menu;
  150. struct PopUp_Item *item;
  151. struct Window *Window;
  152. {  BYTE old_mode = Window->WScreen->RastPort.DrawMode;
  153.  
  154.    if (item == NULL) return;  /* do nothing */
  155.    SetDrMd(&(Window->WScreen->RastPort), COMPLEMENT);
  156.    RectFill(&(Window->WScreen->RastPort), menu->left,
  157.                            menu->top +  item->top -1,
  158.                            menu->left + menu->width -1,
  159.                            menu->top +  item->top + item->height -2);
  160.    SetDrMd(&(Window->WScreen->RastPort), (int)old_mode);
  161. }
  162.  
  163. /* PopUp : this is one of those 'do everything' type of functions. It
  164.  * displays the <menu> in the window  given its upper left hand 
  165.  * coordinates <left,top>.  It tracks the user's mouse movements,
  166.  * highlighting the currently active item until the user deselects
  167.  * the menu by releasing the mouse's select button, at which time,
  168.  * this function will remove the menu from the display. Returns the
  169.  * selection_id of the item that was active when the user releases
  170.  * the select button. Returns 0 if nothing was selected.
  171.  * Assumes that the <menu> has been initialized by a call to 
  172.  * Init_PopUp_Menu and that the user has requested ReportMouse for the
  173.  * Window in question (ReportMouse makes sure that the Window's MouseX and
  174.  * MouseY coordinates are kept up to date).
  175.  */
  176. int PopUp(menu,Window)
  177. struct PopUp_Menu *menu;
  178. struct Window *Window;
  179. { ULONG oldflags;
  180.   SHORT left, top;
  181.  
  182.   left = Window->MouseX;
  183.   top = Window->MouseY;
  184.   if (!Inside_Window(left,top,Window)) return(OUTSIDE_WINDOW);
  185.  
  186.   if ((menu->width <= Window->Width) && (left + menu->width > Window->Width))
  187.      left += Window->Width - (left + menu->width);
  188.  
  189.   if ((menu->height <= Window->Height) && (top + menu->height > Window->Height))
  190.      top += Window->Height - (top + menu->height);
  191.      
  192.   LockLayers(PopUp_LayerInfo);
  193.   /* SwapBits...() requires that the clipping rectangle's bounds are given
  194.    * with respect to the screen's 0,0 coordinate but mouse movements
  195.    * are reported to the Window and are given in terms of the window's
  196.    * coordinate system so...sLeft and sTop represent the adjustment of
  197.    * the Window's coordinates to match the screen's coordinates.
  198.    * Note: if you're using a GIMMEZEROZERO window, you'll have to muck
  199.    * with the left,top coordinates to get the complementing to work.
  200.    */
  201.   left = (left + Window->LeftEdge) & 0xfff0;
  202.   top =  top + Window->TopEdge;
  203.  
  204.   menu->cr.bounds.MinX = left;    
  205.   menu->cr.bounds.MinY = top;
  206.   menu->cr.bounds.MaxX = left + menu->width -1;
  207.   menu->cr.bounds.MaxY = top + menu->height -1;
  208.   SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
  209.  
  210.   menu->left = left;
  211.   menu->top =  top;
  212.   SelectItem(menu,Window);  
  213.   oldflags = Window->IDCMPFlags;
  214.   ModifyIDCMP(Window,oldflags | MOUSEMOVE);
  215.   while (1)  /* wait for the user to select an item and deselect the menu */
  216.      { struct IntuiMessage msg, *message, *GetMsg();
  217.        int MouseMoved = FALSE;
  218.  
  219.        Wait(1 << Window->UserPort->mp_SigBit);
  220.        while (message = GetMsg(Window->UserPort)) { 
  221.             msg = *message;         /* make a backup copy of message */
  222.             ReplyMsg(message);      /* reply immediately to prevent deadlock */
  223.             if (msg.Class == MOUSEMOVE)
  224.                /* just keep track of the fact that the mouse moved */
  225.             MouseMoved = TRUE; 
  226.             else if ((msg.Class == MOUSEBUTTONS) && (msg.Code == menu->deactivate)) {
  227.                 /* user has deselected the menu */
  228.                     ModifyIDCMP(Window,oldflags); /* restore idcmp flags */
  229.                     SelectItem(menu,Window);
  230.                     SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
  231.                     UnlockLayers(PopUp_LayerInfo);
  232.                     if (menu->active_item != NULL)
  233.                        return(menu->active_item->selection_id);
  234.                     else return(NOITEM_SELECTED);
  235.                 } /* end of deselection routine */
  236.             }
  237.        /* 
  238.         * at this point the message queue should be empty so the mouse
  239.         * has stopped for the moment.
  240.         */
  241.           if (MouseMoved)
  242.              SelectItem(menu,Window);
  243.       } 
  244. }
  245.  
  246. Dispose_PopUp(menu)
  247. struct PopUp_Menu *menu;
  248. {
  249.   int i;
  250.   for (i = 0; i < menu->depth; i++)
  251.       if (menu->bitmap.Planes[i] != NULL)
  252.          FreeRaster(menu->bitmap.Planes[i], menu->width, menu->height);
  253. }
  254.            
  255.  
  256.      
  257.      
  258.